package titt.head.request;

import titt.TITTValues;
import titt.head.HeadFactory;
import titt.head.util.AbstractRequest;
import titt.io.IOFactory;
import titt.io.encoding.EncodingFacade;
import titt.type.Type;
import titt.type.TypedObject;
import titt.type.Types;

public class MethodHead extends AbstractRequest {

	private String methodName, path; 
	private TypedObject[] params, internalParams;
	private EncodingFacade ef = IOFactory.createEncodingFacade();
	
	//    /path/method;params?params
	
	public MethodHead(RequestHead req) {
		super.h = req;
		
		path = req.getPath();

		int pathIndex = path.lastIndexOf('/') + 1;
		int internalIndex = path.indexOf(';', pathIndex);	
		int paramIndex = path.indexOf('?', internalIndex > -1? internalIndex : pathIndex);

		if(paramIndex < 0) {
			methodName = null;
			internalParams = params = new TypedObject[0];
		}
		else {
			methodName = path.substring(pathIndex, internalIndex > -1? internalIndex : paramIndex);
		
			internalParams = internalIndex < 0? new TypedObject[0] : decode(path.substring(internalIndex + 1, paramIndex));
			params = decode(path.substring(paramIndex + 1));
		
			path = path.substring(0, pathIndex);
		}
	}
	
	public MethodHead(String methodName, TypedObject[] params, TypedObject[] internalParams, RequestHead req) {
		
		String 	methodPath = req.getPath().indexOf("?") != -1? req.getPath().substring(0, req.getPath().lastIndexOf("/") + 1): req.getPath(), 
				internalEncoded = encode(internalParams, ";", false),
				paramsEncoded = encode(params, "?", true);
		
		if(!methodPath.endsWith("/")) methodPath += "/";
				
		
		path = methodPath;

		methodPath += methodName + internalEncoded + paramsEncoded;
		
		super.h = new Request(req.getHTTPMethod(), methodPath, req);
		
		this.methodName = methodName;
		this.params = params;
		this.internalParams = internalParams;
	}
	
	private String encode(TypedObject[] params, String init, boolean includeOnEmpty) {
		String methodPath = "";
		
		for(TypedObject p : params) {
			if(!ef.isStringEncodeable(p.getType())) continue;
			if(!methodPath.isEmpty()) methodPath += "&";
			
			String enc = ef.encodeToString(p.getType(), p.getObject());
			methodPath += p.getType().asString() + (enc.length() == 0? "" : "=" + enc);
		}
		
		return methodPath.isEmpty() && !includeOnEmpty? "" : init + methodPath;
	}
	
	private TypedObject[] decode(String src) {
		if(src.isEmpty())
			return new TypedObject[0];

		String[] params = src.split("\\&");
		TypedObject[] ret = new TypedObject[params.length];
		
		for(int i = 0; i < params.length; i++) {
			String[] pair = params[i].split("=");

			Type t = new Type(pair[0]);

			ret[i] = new TypedObject(t, pair.length > 1 && ef.isStringDecodeable(t)? ef.decodeFromString(t, pair[1]) : null);
		}
		
		return ret;
	}
			
	public String getNonMethodPath() {
		return path;
	}
	
	public TypedObject[] getParams() {
		return params;
	}
	
	public TypedObject[] getInternalParams() {
		return internalParams;
	}
		
	public String getMethodName() {
		return methodName;
	}
	
	public static void main(String[] args) {
		MethodHead mh = new MethodHead("foo", new TypedObject[]{new TypedObject(Types.STRING, "b;ar"), new TypedObject(Types.INT, 42)}, new TypedObject[]{new TypedObject(Types.toArray(Types.STRING), new String[]{"foo","bar"})}, new Request(TITTValues.GET, "/", HeadFactory.EMPTY));
		System.out.println(mh.getPath());
		MethodHead nmh = new MethodHead(mh);
		System.out.println("nam = " + nmh.getMethodName());
		System.out.println(nmh.getNonMethodPath());
		
		System.out.println(nmh.getParams()[0].getObject());
		System.out.println(((String[])(nmh.getInternalParams()[0].getObject()))[0]);
	}
}
